package cc.shacocloud.mirage.bean.meta;

import lombok.Getter;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * {@link BeanDescription 的默认实现}
 *
 * @author 思追(shaco)
 */
public class BeanDescriptionImpl implements BeanDescription {
    
    /**
     * 当前对象的 {@link BeanKey}
     */
    @Getter
    @NotNull
    private final BeanKey beanKey;
    
    /**
     * 构造函数对象
     */
    @Getter
    @NotNull
    private final BeanConstructor beanConstructor;
    
    /**
     * 注入点对象
     */
    @Getter
    @NotNull
    private final List<BeanInjectionPoint> injectionPoints;
    
    /**
     * 当前对象的所有依赖对象
     */
    @Getter
    @NotNull
    private final List<BeanKey> dependencies;
    
    /**
     * 当前对象是否为单例对象
     */
    @Getter
    private final boolean singleton;
    
    @Getter
    private final boolean lazy;
    
    public BeanDescriptionImpl(@NotNull BeanKey beanKey,
                               @NotNull BeanConstructor beanConstructor,
                               @NotNull List<BeanInjectionPoint> injectionPoints,
                               boolean singleton,
                               boolean lazy) {
        this.beanKey = beanKey;
        this.beanConstructor = beanConstructor;
        this.injectionPoints = injectionPoints;
        this.singleton = singleton;
        this.lazy = lazy;
        this.dependencies = new ArrayList<>();
        
        // 依赖项是 构造函数依赖和注入点依赖的总和
        dependencies.addAll(beanConstructor.getDependencies());
        for (BeanInjectionPoint injectionPoint : injectionPoints) {
            dependencies.addAll(injectionPoint.getDependencies());
        }
    }
    
    /**
     * 获取描述 {@link #getBeanKey()} 中需要依赖关系注入的字段的元数据。
     */
    public List<FieldInjectionPoint> getFields() {
        List<FieldInjectionPoint> fields = new ArrayList<>();
        
        for (BeanInjectionPoint injectionPoint : injectionPoints) {
            if (injectionPoint instanceof FieldInjectionPoint) {
                fields.add((FieldInjectionPoint) injectionPoint);
            }
        }
        
        return fields;
    }
    
    /**
     * 获取描述 {@link #getBeanKey()} 中需要依赖关系注入的方法的元数据。
     */
    public List<MethodInjectionPoint> getMethods() {
        List<MethodInjectionPoint> methods = new ArrayList<>();
        
        for (BeanInjectionPoint injectionPoint : injectionPoints) {
            if (injectionPoint instanceof MethodInjectionPoint) {
                methods.add((MethodInjectionPoint) injectionPoint);
            }
        }
        
        return methods;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BeanDescriptionImpl that = (BeanDescriptionImpl) o;
        return singleton == that.singleton && beanKey.equals(that.beanKey) && beanConstructor.equals(that.beanConstructor) && injectionPoints.equals(that.injectionPoints) && dependencies.equals(that.dependencies);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(beanKey, beanConstructor, injectionPoints, dependencies, singleton);
    }
    
    @Override
    public String toString() {
        return "[singleton=" + isSingleton() + "] " + beanKey;
    }
    
}
